/*
 * @Author: Jinsc
 * @Date: 2023-01-09 09:55:56
 * @LastEditors: Jinsc
 * @LastEditTime: 2023-01-09 10:53:50
 * @FilePath: \lvgl_pm\lvgl_pm.h
 * @Description:
 * Copyright (c) 2023 by jinsc123654@gmail.com All Rights Reserved.
 */
#ifndef LVLG_PM_H
#define LVLG_PM_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#include <stdint.h>


/* 给页面一个专有ID 通过编译器警告 防止打开未知界面 */
typedef enum
{
    PM_ID_HAED = 0,
    PM_ID_START_UP,
    PM_ID_MENU,
    PM_ID_MAIN,
    PM_ID_SETTING_MENU,
    PM_ID_SETTING_TIME,
    PM_ID_TAIL
} lv_pm_id_t;

#define LV_PM_MAJOR 0
#define LV_PM_MINOR 1
#define LV_PM_PATCH 1
#define LV_PM_USE_STA_BAR 1
#define LV_PM_USE_BACK_BAR 1

#ifdef user_lv_simulator
#define lv_pm_printf printf
#else
#define lv_pm_printf(...)
#endif
enum LV_PM_PAGE_ANIMA {
    LV_PM_ANIMA_NONE = 0,         /*不使用过渡动画*/
    LV_PM_ANIMA_SLIDE = 1,        /*滑动动画，页面从右往左出现，从左往右消失 完善*/
    LV_PM_ANIMA_SLIDE_SCALE = 2,  /*滑动并缩放页面，页面从右往左先出现，再放大全屏 暂时没有完善*/
    LV_PM_ANIMA_POPUP = 3,        /*从各方向交错进入  完善*/
    LV_PM_ANIMA_FADE = 4          /*淡入淡出  完善*/
};

/*暂时没有完善*/
enum LV_PM_ANIMA_DIR {
    LV_PM_ANIMA_TOP = 0,
    LV_PM_ANIMA_BOTTOM = 1,
    LV_PM_ANIMA_RIGHT = 2,
    LV_PM_ANIMA_LEFT = 3
};

enum LV_PM_OPEN_TARGET {
    // open in new page 打开一个新的页面 推荐使用此方式打开界面
    LV_PM_TARGET_NEW = 0,
    // replace current page 在当前页面中打开（先关闭当前页面，再打开新页面 该操作不会增加路由表）
    LV_PM_TARGET_SELF = 1,
    // close all page and open in new page 只打开一个当前页面（先关闭所有页面，再打开新页面  改操作尚未完善）
    LV_PM_TARGET_RESET = 2        /*JSC已经优先完善 202-1-7记录*/
};

/**这个结构体会设定打开界面的方式
* 过渡动画，打开方式，动画方向
*/
typedef struct _lv_pm_open_options_t
{
    enum LV_PM_PAGE_ANIMA animation; /* 过渡动画 */
    enum LV_PM_OPEN_TARGET target;   /* 打开方式 */
    enum LV_PM_ANIMA_DIR direction;  /* 动画方向 */
} lv_pm_open_options_t;

typedef void (*lv_pm_lifecycle)(void* pm_page);
typedef struct _lv_pm_page_t
{
    lv_obj_t* page;
    lv_group_t* group;                /* 输入设备组 */
    lv_obj_t* focus_obj;              /* 输入设备聚焦的对象，该对象并非一定使用
                                            只有当部分界面无法自动聚焦时才使用   lv_pm_get_pm_page(pm_page)->focus_obj = btn;
                                            一般无法聚焦都是因为界面第一个子对象就是无法聚焦的对象导致的 可以使用下方代码
                                            lv_pm_get_pm_page(pm_page)->focus_obj = lv_obj_get_child(cont, x); */
    void* user_data;                  /* 由于将所有回调切换为void 所以现在pege可以携带一个 user_data，方便界面切换时向下一级界面传递数据*/
    bool status_bar;                  /* 默认状态是0 这里就以 0为开启 1为关闭 */
    bool back_bar;                    /* 默认状态是0 这里就以 0为开启 1为关闭 */
    /* 完整的生命周期 */
    lv_pm_lifecycle onLoad;           /* 页面创建，你可以在这里执行初始化 */
    lv_pm_lifecycle willAppear;       /* 页面即将被展示 */
    lv_pm_lifecycle didAppear;        /* 页面已经被完整展示 */
    lv_pm_lifecycle willDisappear;    /* 页面即将被隐藏 */
    lv_pm_lifecycle didDisappear;     /* 页面已经被隐藏不可见 */
    lv_pm_lifecycle unLoad;           /* 页面被关闭，你需要在这里释放所有临时内存，否则可能存在泄漏 */
    lv_pm_open_options_t _options;
    bool _back;
} lv_pm_page_t;

inline lv_pm_page_t* lv_pm_get_pm_page(void* pm_page)
{
    return (lv_pm_page_t*)(pm_page);
}

#ifndef LV_PM_PAGE_NUM
#define LV_PM_PAGE_NUM PM_ID_TAIL
#endif

extern int lv_pm_history_len;
extern lv_pm_page_t* lv_pm_router[LV_PM_PAGE_NUM];/* 页面管理数组 */
extern lv_pm_id_t lv_pm_history[LV_PM_PAGE_NUM];  /* 路由表 */
extern lv_pm_open_options_t options_default;
extern lv_pm_open_options_t options_fade;

uint8_t lv_pm_init(void);
int lv_pm_set_page_size_default(lv_coord_t width, lv_coord_t height);
int lv_pm_set_page_default(lv_align_t align, lv_coord_t x_ofs, lv_coord_t y_ofs);
void lv_pm_set_group_default(lv_group_t* group);

/* 创建 设置页面用 */
typedef struct _lv_pm_create_t
{
    lv_pm_page_t* (*create)(lv_pm_id_t id, lv_pm_lifecycle onLoad, lv_pm_lifecycle unLoad);/*这个函数只是注册界面 并不会创建界面 */
    int8_t(*onLoad)(void* page, lv_pm_lifecycle fun);                              /* 页面创建，你可以在这里执行初始化 */
    int8_t(*willAppear)(void* page, lv_pm_lifecycle fun);                          /* 页面即将被展示 */
    int8_t(*didAppear)(void* page, lv_pm_lifecycle fun);                           /* 页面已经被完整展示 */
    int8_t(*willDisappear)(void* page, lv_pm_lifecycle fun);                       /* 页面即将被隐藏 */
    int8_t(*didDisappear)(void* page, lv_pm_lifecycle fun);                        /* 页面已经被隐藏不可见 */
    int8_t(*unLoad)(void* page, lv_pm_lifecycle fun);                              /* 页面被关闭，你需要在这里释放所有临时内存，否则可能存在泄漏 */
    int8_t(*focus_obj)(void* page, lv_obj_t* obj);                                 /* 让界面打开后聚焦这个对象 */
    int8_t(*status_bar)(void* page, bool Enable);                                  /* 是否使能状态栏 */
    int8_t(*back_bar)(void* page, bool Enable);                                    /* 是否使能返回栏 */

}lv_pm_create_t;
extern const lv_pm_create_t lv_pm_create;/* 创建 设置页面用函数集合 */


typedef struct _lv_pm_control_t
{
    uint8_t(*open)(lv_pm_id_t id, lv_pm_open_options_t* behavior);/* 调用open_page后可能会创建一次样式之类的东西 可能会永久让内存增加一部分 再次open_page就不会增加了 */
    uint8_t(*open_user)(lv_pm_id_t id, lv_pm_open_options_t* behavior, void* user_data);/* 打开并向打开的界面写入一个用户数据 */
    uint8_t(*back)(void);                                                               /* 调用此代码会返回上一个路由表记录的界面 */
    uint8_t(*back_user)(void* user_data);                                               /* 调用此代码会返回上一个路由表记录的界面 并向返回的界面用户数据*/
    uint8_t(*back_id)(lv_pm_id_t id);                                                   /* 返回指定的ID界面  该操作是从0遍历路由表进行操作的 */
    void* (*get_user)(void);
    void (*free_user)(void);
}lv_pm_control_t;
extern const lv_pm_control_t lv_pm_control;/* 控制 打开页面用函数集合 */
#ifdef __cplusplus
} /*extern "C"*/
#endif

#endif
